# -*- coding:utf8 -*-
"""
Author: gallopingvijay
Email: 1937832819@qq.com
Website: https://www.choudalao.com
"""
# python3
# from shibie import baiduImg
# from shibie import tx
from datetime import datetime
import time
# import pytesseract
from shibie import baiduBce
import os
import pymysql
# from io import BytesIO
from requests import session
# from PIL import Image
# import PIL.ImageOps
import yaml

# 跟域名
BASE_URL = 'https://investorservice.cfmmc.com'


class Cfmmc(object):
    def __init__(self, username=None, max_gap=2, code_num=10):
        '''
        初始化
        :param username:用户名，为None时，查询所有用户
        :param max_gap:从什么时候开始抓取数据，2表示从两天前开始
        :param code_num:验证码识别次数
        :return:
        '''
        # 配置
        self.configs = self.get_config()
        # 数据库
        self.conn = pymysql.connect(
            host=self.configs['mysql_config']['host'],
            port=self.configs['mysql_config']['port'],
            user=self.configs['mysql_config']['user'],
            password=self.configs['mysql_config']['password'],
            db=self.configs['mysql_config']['db'],
            charset=self.configs['mysql_config']['charset']
        )
        # 创建一个游标
        self.cursor = self.conn.cursor()
        # 账号
        self.users = ()
        # 指定的用户名
        self.username = username
        # 查询区间，从今天往前数的天数
        self.max_gap = max_gap
        # 验证码执行次数
        self.code_num = code_num
        # 消息通知
        self.msg = ''
        # 客户账号状态
        self.user_status = 0
        # 运行时间
        self.run_time = time.strftime(
            '%Y-%m-%d %H:%M:%S', time.localtime(time.time()))

    def pymysql_action(self, sql):
        # 执行 SQL 语句
        self.cursor.execute(sql)
        # 提交
        self.conn.commit()

    def get_config(self):
        '''
        获取config.yaml配置
        :return:configs
        '''
        # 获取当前文件的Realpath
        fileNamePath = os.path.split(os.path.realpath(__file__))[0]
        # 读取文件
        yamlPath = os.path.join(fileNamePath, 'config.yaml')
        # 加上 ,encoding='utf-8'，处理配置文件中含中文出现乱码的情况。
        file = open(yamlPath, 'r', encoding='utf-8')
        # 读取文件
        cont = file.read()
        # 返回配置
        return yaml.safe_load(cont)

    def file_path(self, path, file):
        '''
        返回文件路径
        :param path:路径
        :param file:文件名
        :return:
        '''
        # 是否存在目录
        if not os.path.exists(path):
            os.makedirs(path)
        return path+'/' + file

    # def reg_img(self, file_obj):
    #     '''
    #     OCR识别图片
    #     :param file_obj:文件
    #     :return:
    #     '''
    #     pytesseract.pytesseract.tesseract_cmd = r"D:\Program Files\Tesseract-OCR\tesseract.exe"
    #     im = Image.open(file_obj)
    #     im = im.convert('L')
    #     binary_image = im.point([0 if i < 210 else 1 for i in range(256)], '1')
    #     im1 = binary_image.convert('L')
    #     im2 = PIL.ImageOps.invert(im1)
    #     im3 = im2.convert('1')
    #     im4 = im3.convert('L')
    #     res = pytesseract.image_to_string(im4)
    #     # print(res)
    #     # im4.show()
    #     return res

    def get_download_url(self, content, key='下载'):
        '''
        获取下载链接
        :param content:内容
        :param key:key
        :return:
        '''
        a = content.split(key)[0]
        b = a.split('<div id="waitBody">')[1]
        c = b.split('<a href="')[1]
        d = c.split('" target="_blank">')[0]
        return BASE_URL + d

    def flag_filter(self, content, flag):
        '''
        匹配内容
        :param content:内容
        :param key:key
        :return:
        '''
        if len(content.split(flag)) < 2:
            return ''
        result = content.split(flag)[1].split('"')[0]
        return result

    def get_day(self, gap=1):
        '''
        返回年月日时间，并过滤周末周六
        :param gap:间隔数
        :return:
        '''
        if gap >= self.max_gap:
            return False
        # 时间戳
        day = time.time() - 86400 * (gap - 1)
        # 输出年月日
        ymd = time.strftime('%Y-%m-%d', time.localtime(day))
        # 获取星期几 数字1-7代表周一到周日
        week = datetime.strptime(ymd, '%Y-%m-%d').isoweekday()
        if week > 5:
            print('...' + ymd + '是周' + str(week))
            return True
        return ymd

    def get_dingshi_data(self, ss, user_id, header, token=''):
        '''
        处理逐日盯市页面
        :param ss:request.session
        :param user_id:用户id
        :param header:header
        :param token:token
        :return:
        '''
        for i in range(1, self.max_gap):
            # 获取时间
            ymd = self.get_day(i)
            if ymd is False:  # 说明循环完了
                return True
            elif ymd is True:  # 说明是周末跳过
                continue
            post_data = {
                "org.apache.struts.taglib.html.TOKEN": token,
                "tradeDate": ymd,
                "byType": 'data',
            }
            dingshi_url = BASE_URL+'/customer/setParameter.do'
            dingshi_html = ss.post(dingshi_url,
                                   data=post_data,
                                   headers=header,
                                   timeout=5)
            dingshi_html_code = dingshi_html.content.decode()
            # #看看html内容对不对
            # with open('./other/yemian.html', 'w+',
            #           encoding='utf-8') as files:
            #     files.write(dingshi_html_code)
            if '(逐日盯市)' in dingshi_html_code:
                # 找到下载按钮
                if '下载' in dingshi_html_code:
                    download_url = self.get_download_url(
                        dingshi_html_code, '下载')
                    xls_res = ss.get(download_url, headers=header)
                    # 下载文件
                    file_name = self.file_path(
                        './exel', user_id + '_' + ymd + '.xls')
                    # 判断文件是否存在
                    if os.path.exists(file_name) is True:
                        text = '...' + file_name + '已存在，'
                        print(text)
                        self.msg += text
                        continue
                    print('...准备下载' + file_name + '的数据')
                    with open(file_name, "wb") as xls_file:
                        xls_file.write(xls_res.content)
                else:
                    text = '...' + ymd+'不包含下载按钮，'
                    print(text)
                    self.msg += text
                    continue
            else:
                print('...不是追日盯市页面')
        return True

    def main(self, user_id, passwd):
        '''
        处理逐日盯市页面
        :param user_id:用户id
        :param passwd:passwd
        :return:
        '''
        header = {
            'Connection':
            'keep-alive',
            'User-Agent':
            "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36",
        }
        url = BASE_URL+"/login.do"
        token_flag = 'name="org.apache.struts.taglib.html.TOKEN" value="'
        veri_code_flag = 'src="/veriCode.do?t='
        ss = session()
        res = ss.get(url, headers=header)
        content = res.content.decode()
        token = self.flag_filter(content, token_flag)
        veri_code_url = BASE_URL+'/veriCode.do?t=' + self.flag_filter(
            content, veri_code_flag)
        for i in range(self.code_num):
            print(f'...第{i + 1}次尝试')
            try:
                # OCR识别
                # tmp_file = BytesIO()
                # tmp_file.write(ss.get(veri_code_url).content)
                # veri_code = reg_img(tmp_file)
                # 百度API
                # veri_code = baiduImg.BaiduImg().dealImg(path, type)
                # 百度接口
                tmp_file = self.file_path('./code_img', 'logo_code.jpg')
                req_res = ss.get(veri_code_url).content
                open(tmp_file, 'wb').write(req_res)
                veri_code = baiduBce.BaiduBce().dealImg(tmp_file, 2, True)
                if veri_code and len(veri_code) >= 5:
                    veri_code = ''.join(filter(str.isalnum, veri_code))
                    print('...识别得到:' + veri_code)
                    post_data = {
                        "org.apache.struts.taglib.html.TOKEN": token,
                        "showSaveCookies": '',
                        "userID": user_id,
                        "password": passwd,
                        "vericode": veri_code,
                    }
                    content2 = ss.post(url,
                                       data=post_data,
                                       headers=header,
                                       timeout=5)
                    res = content2.content.decode()
                    if "验证码错误" in res:  # 验证码验证失败
                        print('...验证码不匹配')
                    elif ("用户名或密码错误" in res) or ("您错误尝试超过3次" in res):  # 账号密码不通过
                        text = '...账号密码错误，数据库修改为验证不通过，'
                        print(text)
                        self.msg += text
                        print(text)
                        # 账号密码错误，数据库修改为验证不通过
                        update_sql = "UPDATE `wjf_transaction_users` SET status=3,updated_at='{0}' WHERE username='{1}'".format(
                            self.run_time, user_id)
                        self.pymysql_action(update_sql)
                        # 写入消息通知
                        message_title = user_id+'账号密码不正确'
                        message_text = user_id+'账号密码不正确'
                        message_sql = "INSERT INTO `wjf_messages` (title,text,accept_admin_id,created_at,updated_at) VALUES ('{0}','{1}','{2}','{3}','{4}');".format(
                            message_title, message_text, '-1', self.run_time, self.run_time)
                        self.pymysql_action(message_sql)
                        break
                    elif "登录超时，请重新登录" in res:
                        text = '...登录超时，重新登录，'
                        print(text)
                        self.msg += text
                        print(text)
                        break
                    # elif "资金安全特别提示":  # 如有这这几个字表示登录失败
                    #     text = '...登录失败，'
                    #     print(text)
                    #     self.msg += text
                    #     print(text)
                    #     break
                    else:
                        # 如果客户账号非正常状态，更新为正常
                        if self.user_status != 1:
                            update_sql = "UPDATE `wjf_transaction_users` SET status=1,updated_at='{0}' WHERE username='{1}'".format(
                                self.run_time, user_id)
                            self.pymysql_action(update_sql)
                            # 写入消息通知
                            message_title = user_id+'通过验证'
                            message_text = user_id+'通过验证'
                            message_sql = "INSERT INTO `wjf_messages` (title,text,accept_admin_id,created_at,updated_at) VALUES ('{0}','{1}','{2}','{3}','{4}');".format(
                                message_title, message_text, '-1', self.run_time, self.run_time)
                            self.pymysql_action(message_sql)
                        # 获取页面cookie
                        cookie_dict = dict(ss.cookies)
                        cookie = 'JSESSIONID=' + cookie_dict['JSESSIONID']
                        header['Cookie'] = cookie
                        # 进入逐日盯市页面
                        res = self.get_dingshi_data(
                            ss, user_id, header, token)
                        if res is True:
                            break
                time.sleep(1)
                veri_code_url = BASE_URL+"/veriCode.do?t=" + str(
                    int(time.time() * 1000))
            except Exception as e:
                print(e)
        text = '...' + user_id + '处理结束。'
        print(text)
        self.msg += text

    def get_users(self):
        '''
        获取用户
        :param username:当指定用户是，查询指定的用户
        '''
        if self.username is None:
            users_sql = "SELECT username,ped,status FROM `wjf_transaction_users` WHERE `deleted_at` is NULL"
        else:
            users_sql = "SELECT username,ped,status FROM `wjf_transaction_users` WHERE `deleted_at` is NULL AND `username`="+self.username
        self.pymysql_action(users_sql)
        self.users = self.cursor.fetchall()
        return self.users

    def run(self):
        '''
        入口文件
        '''
        self.users = self.get_users()
        default_max_gap = self.max_gap
        if not bool(self.users):
            print("请添加期货中心账号")
            return False
        for user in self.users:
            self.msg = ''
            # 账号密码必须
            if user[0] is None or user[0] == '':
                text = '...账号为空，'
                print(text)
                continue
            if user[1] is None or user[1] == '':
                text = f'...{user[0]}的密码为空，'
                print(text)
                self.msg += text
                continue
            # 获取客户账号状态
            self.user_status = user[2]
            if default_max_gap == 2:
                # 如果是默认天数，那就按照数据库状态来，如果status为1：表示已验证，只抓取2天的数据，否则就抓取180天的，max_gap
                if self.user_status != 1:
                    self.max_gap = 180
            text = f'账号{user[0]}开始执行，'
            print(text)
            self.msg = text
            self.main(user[0], user[1])
            message_title = '逐日盯市抓取通知'
            message_text = self.msg
            message_sql = "INSERT INTO `wjf_messages` (title,text,accept_admin_id,created_at,updated_at) VALUES ('{0}','{1}','{2}','{3}','{4}');".format(
                message_title, message_text, '-1', self.run_time, self.run_time)
            self.pymysql_action(message_sql)

    def __del__(self):
        # 关闭游标
        self.cursor.close()
        # 关闭数据库连接
        self.conn.close()


if __name__ == '__main__':
    '''
    模拟登陆 中国期货市场监控中心，抓取逐日盯市数据
    '''
    obj = Cfmmc()
    res = obj.run()
